package com.quectel.business.dms.application;

import com.google.common.base.Preconditions;
import com.quectel.business.dms.AccessorUtils;
import com.quectel.business.dms.application.access.Accessor;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.application.dto.ApplicationDto;
import com.quectel.core.module.application.service.ApplicationAccessConfService;
import com.quectel.core.module.application.service.ApplicationService;
import com.quectel.core.module.device.dto.DeviceTypeDto;
import com.quectel.core.module.device.service.DeviceTypeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * @author rananxin
 * @date 2021/11/19 11:30 上午
 */
@Component
@Slf4j
public class ApplicationBusiness {

    @DubboReference
    private ApplicationService applicationService;
    @DubboReference
    private ApplicationAccessConfService applicationAccessConfService;
    @DubboReference
    private DeviceTypeService deviceTypeService;

    /**
     * 获取唯一应用 作用类似于 selectByAppId()
     *
     * @param tenantId       租户id
     * @param deviceTypeCode 设备类型code
     * @param confCodeEnum   接入方式枚举
     * @param configMap      可唯一确定应用的接入配置
     * @return
     */
    public ApplicationDto getOnlyApplication(Long tenantId, String deviceTypeCode
            , ApplicationAccessConf.ConfCodeEnum confCodeEnum, Map<String, Object> configMap) {

        Preconditions.checkNotNull(tenantId);
        Preconditions.checkNotNull(deviceTypeCode);
        Preconditions.checkNotNull(confCodeEnum);
        Preconditions.checkNotNull(configMap);

        List<ApplicationDto> applications = getApplications(tenantId, deviceTypeCode, confCodeEnum, configMap);
        if (CollectionUtils.isNotEmpty(applications)) {
            return applications.get(0);
        }
        return null;
    }

    /**
     * @param optionalTenantId       租户id (可为null)
     * @param optionalDeviceTypeCode 设备类型code （可为null）
     * @param confCodeEnum           接入方式枚举
     * @param configMap              可唯一确定应用的接入配置
     * @return
     */
    public List<ApplicationDto> getApplications(Long optionalTenantId, String optionalDeviceTypeCode
            , ApplicationAccessConf.ConfCodeEnum confCodeEnum, Map<String, Object> configMap) {

        Preconditions.checkNotNull(confCodeEnum);
        Preconditions.checkNotNull(configMap);

        DeviceTypeDto deviceTypeDto = null;
        if (StringUtils.isNotBlank(optionalDeviceTypeCode)) {
            deviceTypeDto = deviceTypeService.selectByCode(optionalDeviceTypeCode);
        }
        List<String> configUniqueFlag = ApplicationAccessConf.getConfigUniqueFlag(confCodeEnum.getCode());
        return applicationService
                .selectCacheByFlag(confCodeEnum.getCode(), configUniqueFlag, configMap, optionalTenantId,
                        deviceTypeDto != null ? deviceTypeDto.getId() : null);
    }

    /**
     * 反射接入方式的init方法
     *
     * @param applicationDto 应用dto
     */
    public void init(ApplicationDto applicationDto, boolean isFromTask) {

        DeviceTypeDto deviceTypeDto = deviceTypeService.selectById(applicationDto.getDeviceTypeId());

        if (deviceTypeDto == null) {
            return;
        }
        if (!isFromTask) {
            ApplicationDto newlyApp = new ApplicationDto();
            newlyApp.setId(applicationDto.getId());
            newlyApp.setInitStatus(SystemConstants.ABNORMAL);
            applicationService.updateById(newlyApp);
        }
        try {
            Accessor baseAccessor = AccessorUtils.getBaseAccessor(deviceTypeDto);
            assert baseAccessor != null;
            boolean isSuccess = baseAccessor.initApplication(applicationDto);

            if (!isFromTask) {
                ApplicationDto newlyApp = new ApplicationDto();
                newlyApp.setId(applicationDto.getId());
                newlyApp.setInitStatus(isSuccess
                        ? SystemConstants.NORMAL
                        : SystemConstants.ABNORMAL);
                applicationService.updateById(newlyApp);
            }
        } catch (Exception e) {
            log.error("Exception", e);
        }
    }

}
